package entities;

import force.Force;
import backbone.IForceable;
import backbone.IUpdatable;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Point2D;
import main.Simulation;



/**
 *
 * @author Robert C. Duvall
 */
public class Mass extends PointObject implements IForceable, IUpdatable{

    private static final int DOWN = 90;
    private static final int LEFT = 180;
    private static final int RIGHT = 270;
    private double myMass;
    private Force myAcceleration;
    private Force myVelocity;


    /**
     * @param id indicates id of mass object
     * @param x coordinate of the mass
     * @param y coordinate of the mass
     * @param mass mass in kg of the mass object
     */
    public Mass (int id, double x, double y, double mass) {
        super(id, x, y);
        myMass = mass;
        myAcceleration = new Force();
        setVelocity(0, 0);
    }
    
    public double getMass() {
        return myMass;
    }
    
    /**
     * @param f force applied on this mass
     */
    public void applyForce (Force f) {
        myAcceleration.sum(f);
    }
    
    /**
     * Returns shape's velocity.
     */
    public Force getVelocity () {
        return myVelocity;
    }
    
    /**
     * @param direction direction of force
     * @param magnitude magnitude of force
     */
    public void setVelocity (double direction, double magnitude) {
        myVelocity = new Force(direction, magnitude);
    }

    /**
     * @return point object acceleration
     */
    public Force getAcceleration() {
        return myAcceleration;
    }
    @Override
    public void paint (Graphics2D pen) {
        pen.setColor(Color.BLACK);
        pen.fillOval(getLeft(), getTop(), getSize().width, getSize().height);
    }

   
    private Force getBounce (Dimension bounds) {
        Force impulse = new Force();
        if (getLeft() < 0) {
            impulse = new Force(0, 2);
            setCenter(getSize().width / 2, getCenter().getY());
        }

        else if (getRight() > bounds.width) {
            impulse = new Force(LEFT, 2);
            setCenter(bounds.width - getSize().width / 2, getCenter().getY());
        }
        if (getTop() < 0) {
            impulse = new Force(RIGHT, 2);
            setCenter(getCenter().getX(), getSize().height / 2);
        }
        else if (getBottom() > bounds.height) {
            impulse = new Force(DOWN, 2);
            setCenter(getCenter().getX(), bounds.height - getSize().height / 2);
        }
        impulse.scale(getVelocity().getRelativeMagnitude(impulse));
     
        return impulse;
    }


    @Override
    public void update (Simulation canvas, double dt) {
        applyForce(getBounce(canvas.getSize()));
        getVelocity().sum(getAcceleration());
        getAcceleration().reset();
        move(dt);
    }
    
    public Point2D getPosition() {
        return getCenter();
    }
    
    
    /**
     * 
     * @param dt Update position based on movement in time dt.
     */
    private void move(double dt) {
        getCenter().setLocation(getCenter().getX()
                + getVelocity().getXChange() * dt,
                getCenter().getY() + getVelocity().getYChange() * dt);
    }
}
